package de.ttf.ts.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;

@MappedSuperclass
public abstract class BaseEntity<T extends BaseEntity<T>> implements Serializable {

    private static final long serialVersionUID = 1L;

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Long id;

    @Version
    private long version;

    public boolean isVersion(Long version) {
        return this.version == version;
    }

    public long getVersion() {
        return version;
    }

    public void setVersion(long version) {
        this.version = version;
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public EntityInfo<T> getInfo() {
        return id != null ? new EntityInfo<T>(this) : null;
    }

    @Override
    public int hashCode() {
        if (this.getId() == null) {
            return super.hashCode();
        } else {
            return this.getId().hashCode();
        }
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof BaseEntity)) {
            return false;
        }

        if (!isAssignableFrom(this.getClass(), obj.getClass()) && !isAssignableFrom(obj.getClass(), this.getClass())) {
            return false;
        }

        BaseEntity<?> other = (BaseEntity<?>) obj;
        if (this.getId() == null && other.getId() == null) {
            return super.equals(other);
        }

        if (this.getId() == null || other.getId() == null) {
            return false;
        }

        return this.getId().equals(other.getId());
    }

    private boolean isAssignableFrom(Class<?> classA, Class<?> classB) {
        // GWT cannot use isAssignableFrom or isInstance, see:
        // http://code.google.com/intl/de-DE/webtoolkit/doc/1.6/RefJreEmulation.html
        //
        // return classA.isAssignableFrom(classB);

        Class<?> superClass = classB;
        do {
            if (superClass == classA) {
                return true;
            }
        } while ((superClass = superClass.getSuperclass()) != null);
        return false;
    }

    protected String nullIfEmpty(String value) {
        return "".equals(value) ? null : value;
    }

    public static String toUpperCase(String value) {
        return value != null ? value.toUpperCase() : null;
    }

    public static char getCharAtIndex(String value, int index) {
        return value != null ? value.charAt(index) : 0;
    }
    
    public static <T extends BaseEntity<T>> EntityInfo<T> getInfo(T entity) {
    	return entity != null ? entity.getInfo() : null;
    }

    public static <T extends BaseEntity<T>> Collection<EntityInfo<T>> getInfos(Iterable<T> entities) {
        List<EntityInfo<T>> infos = new ArrayList<EntityInfo<T>>();
        for (T entity : entities) {
            infos.add(entity.getInfo());
        }
        return infos;
    }

    public static <T extends BaseEntity<T>> Collection<Long> getIds(Collection<T> entities) {
        List<Long> infos = new ArrayList<Long>();
        for (T entity : entities) {
            infos.add(entity.getId());
        }
        return infos;
    }
}